﻿using Modbus.Device;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using thinger.DataConvertLib;

namespace 随机模拟
{
    /// <summary>
    /// 基于NModbus封装的ModbusTCP类
    /// </summary>
    public class NModbusTcp
    {
        //定义一个TCP客户端
        private TcpClient client;
        //定义一个Modbus主站
        private ModbusIpMaster master;
        //是否连接
        public bool IsConnnect { get; set; } = false;

        /// <summary>
        /// 连接设备
        /// </summary>
        /// <param name="ip">IP地址</param>
        /// <param name="port">端口号</param>
        /// <returns></returns>
        public int Connect(string ip, int port)
        {
            if (IsConnnect)
            {
                //已经连接成功，无需再次连接
                return 0;
            }
            //初始化一下
            client = null;
            master = null;
            try
            {
                //实例化一个客户端
                client = new TcpClient();
                //设置soket操作
                client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 30);
                //发送数据超时时间
                client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 30);
                //连接
                client.Connect(IPAddress.Parse(ip), port);
                //实例化modbustcp主站
                master = ModbusIpMaster.CreateIp(client);
                //重试次数
                master.Transport.Retries = 3;
                //读取数据超时时间
                master.Transport.ReadTimeout = 1000;
                //连接标志置true
                IsConnnect = true;
                //连接成功
                return 1;
            }
            catch
            {
                if (client != null)
                {
                    //释放资源
                    client.Close();
                    client = null;
                }
                if (master != null)
                {
                    //释放资源
                    master.Dispose();
                    master = null;
                }
                //连接标志置false
                IsConnnect = false;
            }
            //连接失败
            return 2;

        }

        /// <summary>
        /// 断开连接
        /// </summary>
        public void Disconnect()
        {
            if (client != null)
            {
                //释放资源
                client.Close();
                client = null;
            }
            if (master != null)
            {
                //释放资源
                master.Dispose();
                master = null;
            }
            //连接标志置false
            IsConnnect = false;
        }


        /// <summary>
        /// 读取输入输出线圈
        /// </summary>
        /// <param name="slaveID">从站地址</param>
        /// <param name="startAddress">起始地址</param>
        /// <param name="length">读取长度</param>
        /// <returns></returns>
        public bool[] ReadCoils(ushort startAddress, ushort length = 1, byte slaveID = 1)
        {
            if (master == null) return null;
            bool[] rCoil = null;
            rCoil = master.ReadCoils(slaveID, startAddress, length);
            return rCoil;
        }

        /// <summary>
        /// 读取输入线圈
        /// </summary>
        /// <param name="slaveID">从站地址</param>
        /// <param name="startAddress">起始地址</param>
        /// <param name="length">读取长度</param>
        /// <returns></returns>
        public bool[] ReadInputs(ushort startAddress, ushort length = 1, byte slaveID = 1)
        {
            if (master == null) return null;
            bool[] rInputs = null;
            rInputs = master.ReadInputs(slaveID, startAddress, length);
            return rInputs;
        }

        /// <summary>
        /// 读取保持型寄存器
        /// </summary>
        /// <param name="slaveID">从站地址</param>
        /// <param name="startAddress">起始地址</param>
        /// <param name="length">读取长度</param>
        /// <returns></returns>
        public ushort[] ReadHoldingRegister(ushort startAddress, ushort length = 2, byte slaveID = 1)
        {
            if (master == null) return null;
            ushort[] rhreg = null;
            rhreg = master.ReadHoldingRegisters(slaveID, startAddress, length);
            return rhreg;
        }

        /// <summary>
        /// 读取float
        /// </summary>
        /// <param name="startAddress"></param>
        /// <param name="length"></param>
        /// <param name="slaveID"></param>
        /// <returns></returns>
        public float ReadFloat(ushort startAddress, ushort length = 2, byte slaveID = 1)
        {
            //大端模式是指数据的低位保存在内存的高位地址中，数据的高位保存在内存的低位地址中。
            //小端模式是指数据的低位保存在内存的低位地址中，数据的高位保存在内存的高位地址中。
            //ABCD = 0, // 大端形式
            //BADC = 1, // 大端单字反转
            //CDAB = 2, // 小端单字反转
            //DCBA = 3, // 小端形式
            var data = ReadHoldingRegister(startAddress, length, slaveID);
            //float[] floats = new float[data2.Length / 2];
            //floats = FloatLib.GetFloatArrayFromByteArray(ByteArrayLib.GetByteArrayFromUShortArray(data2), DataFormat.CDAB);
            float[] floats = new float[data.Length];

            byte[] bytes = ByteArrayLib.GetByteArrayFromUShortArray(data, DataFormat.ABCD);
            floats = FloatLib.GetFloatArrayFromByteArray(bytes);

            return floats[0];
        }
        public short ReadShort(ushort startAddress, ushort length = 2, byte slaveID = 1)
        {
            var data = ReadHoldingRegister(startAddress, length, slaveID);
            short[] shorts = new short[data.Length];
            for (int i = 0; i < data.Length; i++)
            {
                byte[] bytes = ByteArrayLib.GetByteArrayFromUShort(data[i], DataFormat.ABCD);
                shorts[i] = ShortLib.GetShortFromByteArray(bytes);
            }

            return shorts[1];
        }

        public string ReadCommon(Variable variable)
        {

            switch (variable.VariableType)
            {
                case "bool":
                    bool[] bools = ReadCoils(variable.VariableAddress);
                    return bools[0].ToString();
                case "short":
                    short s = ReadShort(variable.VariableAddress);
                    return s.ToString();
                case "float":

                    float f = ReadFloat(variable.VariableAddress);
                    return f.ToString();
            }


            return null;
        }


        /// <summary>
        /// 读取输入寄存器
        /// </summary>
        /// <param name="slaveID">从站地址</param>
        /// <param name="startAddress">起始地址</param>
        /// <param name="length">读取长度</param>
        /// <returns></returns>
        public ushort[] ReadInputRegister(ushort startAddress, ushort length = 1, byte slaveID = 1)
        {
            if (master == null) return null;
            ushort[] rireg = null;
            rireg = master.ReadInputRegisters(slaveID, startAddress, length);
            return rireg;
        }

        /// <summary>
        /// 写入单个线圈
        /// </summary>
        /// <param name="slaveID">从站地址</param>
        /// <param name="coilAddress">起始地址</param>
        /// <param name="value">读取长度</param>
        public void WriteSingleCoil(ushort coilAddress, bool value, byte slaveID = 1)
        {
            if (master == null) return;
            master.WriteSingleCoil(slaveID, coilAddress, value);
        }
        /// <summary>
        /// 写入单个寄存器
        /// </summary>
        /// <param name="slaveID">从站地址</param>
        /// <param name="registerAddress">起始地址</param>
        /// <param name="value">读取长度</param>
        public void WriteSingleRegister(ushort registerAddress, ushort value, byte slaveID = 1)
        {
            if (master == null) return;
            master.WriteSingleRegister(slaveID, registerAddress, value);
        }

        /// <summary>
        /// 写入多个线圈
        /// </summary>
        /// <param name="slaveID">从站地址</param>
        /// <param name="startAddress">起始地址</param>
        /// <param name="value">读取长度</param>
        public void WriteMultipleCoils(ushort startAddress, bool[] value, byte slaveID = 1)
        {
            if (master == null) return;
            master.WriteMultipleCoils(slaveID, startAddress, value);

        }
        /// <summary>
        /// 写入多个寄存器
        /// </summary>
        /// <param name="slaveID">从站地址</param>
        /// <param name="startAddress">起始地址</param>
        /// <param name="value">读取长度</param>
        public void WriteMultipleRegisters(ushort startAddress, ushort[] value, byte slaveID = 1)
        {
            if (master == null) return;
            master.WriteMultipleRegisters(slaveID, startAddress, value);

        }
    }
}
